package com.zy.debugger;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.sun.jdi.*;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.Transport;
import com.sun.jdi.connect.Connector.Argument;
import com.sun.jdi.event.*;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;

public class TestJVM {

    private static final String DT_SOCKET = "dt_socket";
    private static final String DT_SHMEN = "dt_shmen";
    private static final String HOST = "hostname";
    private static final String PORT = "port";
    private static final String NAME = "name";
    private static VirtualMachine vm;
    private AttachingConnector getAttachingConnector() {
        VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
        List<AttachingConnector> connectors = vmm.attachingConnectors();
        AttachingConnector socketAttachingConnector = null;
        for (int index = 0; index < connectors.size(); index++) {
            Connector connector = connectors.get(index);
            Transport transport = connector.transport();
            if (DT_SOCKET.equals(transport.name())) {
                socketAttachingConnector = (AttachingConnector) connector;
                break;
            }
        }
        return socketAttachingConnector;
    }

    private Map<String, ? extends Connector.Argument> getConnectorArgument(String name)
            throws Exception {
        AttachingConnector socketAttachingConnector = getAttachingConnector();
        if (socketAttachingConnector == null) {
            throw new Exception("Shared memory attaching connector not found!");
        }
        Map<String, ? extends Connector.Argument> arguments = socketAttachingConnector
                .defaultArguments();
        Connector.Argument nameArgument = arguments.get(NAME);
        nameArgument.setValue(name);
        return arguments;
    }

    private Map<String, ? extends Connector.Argument> getConnectorArgument(String host,
                                                                           String port) throws Exception {
        AttachingConnector socketAttachingConnector = getAttachingConnector();
        if (socketAttachingConnector == null) {
            throw new Exception("Shared memory attaching connector not found!");
        }
        Map<String, ? extends Connector.Argument> arguments = socketAttachingConnector
                .defaultArguments();
        Connector.Argument hostArgument =arguments.get(HOST) ;
        Connector.Argument portArgument =arguments.get(PORT) ;
        hostArgument.setValue(host);
        portArgument.setValue(port);
        return arguments;
    }

    public VirtualMachine getRemoteJVM(String...out) throws Exception{
        AttachingConnector connector = getAttachingConnector();
        Map<String, ? extends Argument> arguments = null;
        VirtualMachine vm = null;

        if(out!=null && out.length ==1){
            arguments = getConnectorArgument((String)out[0]);
        }else if(out != null && out.length ==2){
            arguments = getConnectorArgument((String)out[0],(String)out[1]);
        }else{
            throw new Exception("Invalidate arguments.........");
        }
        try {
            vm = connector.attach(arguments);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return vm;
    }


    public void terminateThread() throws Exception {

         vm = getRemoteJVM("82.156.26.208","8888");

        System.out.println("JVM name ---------->" + vm.name());
        System.out.println("JVM version ---------->" + vm.version());
        System.out.println("JVM description ---------->" + vm.description());


        Iterator iter = vm.allClasses().iterator();
        ReferenceType  rt=null;
        while ( iter.hasNext()) {
            ReferenceType refType = (ReferenceType) iter.next();
            if (refType.isPrepared() && refType.name().equals("com.zy.debugger.DebuggerApplication")) {
                rt=refType;
                break;
            }
        }
        Location location = null;
        List locations = rt.locationsOfLine(21);
        if (locations!=null && locations.size()>0){
            location = (Location) locations.get(0);
            EventRequestManager erm = vm.eventRequestManager();
            EventRequest er = erm.createBreakpointRequest(location);
            er.setSuspendPolicy(EventRequest.SUSPEND_ALL);
            er.enable();
        }




//        if (vm != null) {
//            List<ThreadReference> threads = vm.allThreads();
//            ThreadReference tr = null;
//            int loop = 0;
//            for (; loop < threads.size(); loop++) {
//                tr = threads.get(loop);
//                System.out.print("Thread[" + tr.name() + "] : ");
//                switch (tr.status()) {
//                    case ThreadReference.THREAD_STATUS_MONITOR:
//                        System.out.println(" Waiting");
//                        break;
//                    case ThreadReference.THREAD_STATUS_NOT_STARTED:
//                        System.out.println(" Not Start");
//                        break;
//                    case ThreadReference.THREAD_STATUS_RUNNING:
//                        System.out.println(" Running");
//                        break;
//                    case ThreadReference.THREAD_STATUS_SLEEPING:
//                        System.out.println(" Sleepping");
//                        break;
//                    case ThreadReference.THREAD_STATUS_UNKNOWN:
//                        System.out.println(" Unknow");
//                        break;
//                    case ThreadReference.THREAD_STATUS_WAIT:
//                        System.out.println(" Wait");
//                        break;
//                    case ThreadReference.THREAD_STATUS_ZOMBIE:
//                        System.out.println(" Finish");
//                        break;
//                }
//            }
//            vm.resume();
//            vm.dispose();
//        }

    }

    public static void main(String args[]) throws Exception {
        TestJVM tJVM = new TestJVM();
        tJVM.terminateThread();
        tJVM.eventLoop();
    }
    private static EventQueue eventQueue;
    private static boolean vmExit = false;
    private static EventSet eventSet;
    private static void eventLoop() throws Exception {
        eventQueue = vm.eventQueue();
        while (true) {
            if (vmExit == true) {
                System.out.println("vmexit");
                break;
            }
            eventSet = eventQueue.remove();
            EventIterator eventIterator = eventSet.eventIterator();
            while (eventIterator.hasNext()) {
                Event event = (Event) eventIterator.next();
                execute(event);
                if (!vmExit) {
                    eventSet.resume();
                }
            }
        }
    }

    private static void execute(Event event) throws Exception {
        if (event instanceof VMStartEvent) {
            System.out.println("VM started");
        } else if (event instanceof MethodEntryEvent) {
            Method method = ((MethodEntryEvent) event).method();
            System.out.printf("Enter -> Method: %s, Signature:%s\n",method.name(),method.signature());
            System.out.printf("\t ReturnType:%s\n", method.returnTypeName());
        } else if (event instanceof MethodExitEvent) {
            Method method = ((MethodExitEvent) event).method();
            System.out.printf("Exit -> method: %s\n",method.name());
        } else if (event instanceof VMDisconnectEvent) {
            vmExit = true;
        }
    }
}